package bg.btanev.eightyfour.gwtfacade.converter;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import java.util.SortedSet;
import java.util.TreeSet;

import org.apache.commons.lang.Validate;

import bg.btanev.eightyfour.domain.entitybase.Domain;
import bg.btanev.eightyfour.shared.dto.dtobase.DomainDto;

/**
 *
 * @author B.Tanev
 *
 */
class DtoConverterImpl implements DtoConverter {
	private final ConverterConfiguration config;
	private final ReflectionUtils reflectionUtils;

	DtoConverterImpl(ConverterConfiguration configuration) {
		Validate.notNull(configuration);

		this.config = configuration;
		this.reflectionUtils = new ReflectionUtils(this.config);
	}

	@Override
	public <DTO extends DomainDto, D extends Domain> DTO domainToDto(D source) {
		return domainToDto(source, DEFAULT_COPY_DEPTH);
	}

	@SuppressWarnings("unchecked")
	@Override
	public <DTO extends DomainDto, D extends Domain> DTO domainToDto(D source, int depth) {
		Validate.notNull(source);
		Validate.isTrue(depth >= 0);

		Class<Serializable> sinkClazz = this.config.getAssociation(source.getClass());
		if (sinkClazz == null) {
			throw new IllegalArgumentException(String.format("Sink class for sourse '%s' not found.", source));
		}

		DTO sink = (DTO) reflectionUtils.initClass(sinkClazz);
		if (sink != null) {
			reflectionUtils.copyObjectField(source, sink, depth);
		}

		return sink;
	}

	@Override
	public <DTO extends DomainDto, D extends Domain> D dtoToDomain(DTO source) {
		Validate.notNull(source);

		// TODO Auto-generated method stub
		return null;
	}

	@SuppressWarnings("unchecked")
	@Override
	public <DTO extends DomainDto, D extends Domain, CDTO extends Collection<DTO>, CD extends Collection<D>> CDTO collectionDomainToDto(
			CD sourceCollection, int depth) {

		Validate.notNull(sourceCollection);
		Validate.isTrue(depth >= 0);

		CDTO sinkCollection = null;
		int size = sourceCollection.size();
		if (size > 0) {
			if (sourceCollection instanceof List<?>) {
				sinkCollection = (CDTO) new ArrayList<DTO>(size);
			} else if (sourceCollection instanceof SortedSet<?>) {
				sinkCollection = (CDTO) new TreeSet<DTO>();
			} else if (sourceCollection instanceof Set<?>) {
				sinkCollection = (CDTO) new HashSet<DTO>(size);
			} else if (sourceCollection instanceof Collection<?>) {
				sinkCollection = (CDTO) new ArrayList<DTO>(size);
			}

			if (sinkCollection != null) {
				Iterator<D> iterator = sourceCollection.iterator();
				while (iterator.hasNext()) {
					D d = (D) iterator.next();
					DTO dto = domainToDto(d, depth);
					if (dto != null) {
						sinkCollection.add(dto);
					}
				}
			}
		}

		return sinkCollection;
	}

	@Override
	public <DTO extends DomainDto, D extends Domain, CDTO extends Collection<DTO>, CD extends Collection<D>> CD collectionDtoToDomain(
			CDTO sourceCollection) {

		Validate.notNull(sourceCollection);

		// TODO Auto-generated method stub

		return null;
	}
}
